package com.daji.concurrency.multithread_future_callback;

import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.*;


/*
    该测试结果完全满足需求。
    下面代码的目标：使用线程池调用远程API，远程API会返回一串id
    远程API有一定概率返回失败，返回失败的状态码总是 -10086

    线程池接收API返回结果，如果成功，就将该id回写数据库
    如果失败，就调用异常处理逻辑。

    API参考资料：https://www.cnblogs.com/wuwuyong/p/15496841.html
*/
public class E06_CompletableFuture_AsyncCallback {

    //定义线程池
    //和实施讨论并且根据业务数量，将线程池的参数调整如下：有20个常驻线程。
    public static final ExecutorService threadPool =
            new ThreadPoolExecutor(
                    20,
                    50,
                    60L,
                    TimeUnit.SECONDS,
                    new ArrayBlockingQueue<>(50),
                    new ThreadPoolExecutor.AbortPolicy());


    public static void main(String[] args) {


        //一共需要发送15次远程请求，向数据库回写15次状态
        for (int i = 0; i < 15; i++) {

            //该方法可以传入自定义线程池，否则就用默认的线程池；
            CompletableFuture<Integer> thread = CompletableFuture.supplyAsync(
                    () -> callRemoteApi(), threadPool);

            //线程池执行完毕，如果成功了，则回写,如果失败了，就执行失败处理逻辑
            thread.whenCompleteAsync(
                    (result,throwable)-> {
                        if (result != -10086) //如果线程池返回了调用远程API成功的结果，那么就调用回写数据库的方法
                            writeBack(result);
                        else
                            exceptionHandle(result);//执行失败处理逻辑
                    }
            );

        }


    }
    //调用一个远程API，该API会返回一个id
    private static Integer callRemoteApi(){
        try {
            //模拟长任务：调用时间。该调用时间比较慢，长达三秒
            Thread.sleep(3000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Random random = new Random();
        int i = random.nextInt(10);
        if (judgeSuccess()) {
            System.out.println("已经调用远程API接口，此次调用成功，返回的id是："+i);
            return i;
        } else {
            System.out.println("已经调用远程API接口，此次调用失败");
            return -10086;
        }
    }

    private static void writeBack(int id) {
        //回写状态到数据库是一个短任务（相对而言）
        System.out.println("已经将id为：" + id + "的单据，回写状态到数据库");
    }

    //如果远程调用失败了就进行异常处理。
    private static void exceptionHandle(int code){
        System.out.println("本次调用失败，已经调用失败处理逻辑。错误码为："+code);
    }

    //调用远程接口有50%的概率失败。这个方法用于判断是否接口调用成功
    private static boolean judgeSuccess() {
        Random random = new Random();
        int i = random.nextInt(10);
        if (i <= 5) {
            return true;
        } else {
            return false;
        }
    }
}
